#####
#
# 02/27/2011
# Clint Kitson - EMC vSpecialist - @clintonskitson 
# EMC Community Network - Everything VMware at EMC
# https://community.emc.com/community/connect/everything_vmware?view=overview
#
# 03/30/11 Version 1.21 (suggested currently for non-production use and lab use only, provided as-is)
#
# get_unified_nas_perf.ps1 - collect and process statistics from a EMC Unified storage array NAS protocols
#
# 02/28/11 updated outcsv to ensure same datetime is used during sampling
# 03/14/11 updated to fix intermittent trim error
# 03/14/11 fixed missing volume measures when specifying nfsexport under dart6
# 03/16/11 fixed wrong datamover selection based on nfsexport
# 03/30/11 fixed intermitten problem with fs info being displayed instead of stats
# 08/22/11 fixed columns not being consistent due to changing columns- csv file is now authoritative for future writes
# 09/19/11 ensure 0's are displayed in null metrics from server_stats command
# 09/20/11 don't display row with datamover on line by itself
#
# PARAMETERS
# -paint = adding a -paint will tell the script to refresh stats to same window and refresh stats continuously until interrupted
# -interval (15 seconds default) = the sampling period to collect performance stats
# -metrics = which metrics (columns) to be returned, * will return all columns
#
# -csip = control station IP
# -datamover = datamover (default server_2)
# -nfsexport = nfs export name (ex. export1) if dm is not specified
# -sleep (default 5 seconds) = amount of time to wait in between set of performance samplings
# -outcsv = output to a csv file
#
# EXAMPLE
# .\get_unified_nas_perf.ps1 -csip csip -username root -password pass
# .\get_unified_nas_perf.ps1 -csip csip -username root -password pass -nfsexport cel35-irv-NFS1 -paint -interval 5
# .\get_unified_nas_perf.ps1 -csip csip -username nasadmin -password xx -objects net.device,store,sys.cpuUtil,nfs.basic -nfsexport cel35-IRV-NFS1
# .\get_unified_nas_perf.ps1 -csip csip -username root -password pass -outcsv test.csv
#
#####


param($csip,$username,$password,[string]$objects,$nfsexport,$datamover,[switch]$paint,[string]$interval,$metrics,[string]$sleep,$outcsv)

$objects = $objects.replace(' ',',')

$spath = (Split-Path -parent $MyInvocation.MyCommand.Definition) + "\ssh_function.ps1"
. $spath

# for differences in NAS versions and cpu
if(!$objects) { $objects_d5 = "net.device,store,sys.cpuUtil,nfs.basic"
                $objects_d6 = "net.device,store,kernel.cpu.utilization.cpuUtil,nfs.basic,nfs.v3.op.ALL-ELEMENTS.avgTime" }

if(!$metrics) { [array]$metrics = "Name,Util %,Network In KiB/s,Network Out KiB/s,Network In Pkts/s,Network Out Pkts/s,Network In Errors/s,Network Out Errors/s,Queue Depth,Read Ops/s,Write Ops/s,Read KiB/s,Write KiB/s,Avg Read Size Bytes,Avg Write Size Bytes,Op v3Read Op uSec/Call,Op v3Write Op uSec/Call,Avg uSec/Call".split(',') }
if(!$interval) { $interval = 15 }
if(!$sleep) { $sleep = 5 }
if(!$datamover) { $datamover = "server_2" }

if (!($csip -and $username -and $password)) {
    write-host failed to sepcify -csip, -username, -password
    exit
}

for($z) {
    ## establish the connection to the control station and gather relevant information
    New-SshSession $username $password $csip
    send-ssh 'export NAS_DB=/nas;'
    $version = invoke-ssh "/nas/bin/nas_version | cut -d '.' -f 1;uname -a" "GNU/Linux"
    $tline = $version | select-string -pattern 'nas_version' | %{ $_.LineNumber } | select -last 1    
    if ([string]$version[$tline][0] -eq "5") { $objects=$objects_d5 } else { $objects=$objects_d6 }

    send-ssh "objects='$objects';ts='-terminationsummary yes';interval='$interval'"
    
    if($nfsexport) {
        $mounts = invoke-ssh '/nas/bin/server_mount ALL | tr -d \";uname -a' "GNU/Linux"
        #$mounts;exit
        ## parse mount info and grab fs and datamover
        #$datamover=((($mounts -match " : |\/$nfsexport ") | out-string).replace(" ","").replace(":","").TrimEnd())
        [array]$tmp = ($mounts | select-string -pattern " : |\/$nfsexport ") | %{ $_.Line }
        $datamover=$tmp | select-string -pattern "\/$nfsexport "| %{ $tmp[$_.LineNumber-2].replace(" ","").replace(":","").TrimEnd() }
        
        $fs=(($mounts -match "/$nfsexport ") |  out-string).split(' ')[0]
        
        ## parse mount info and grab mounting parameters 
        $mntparams=(($mounts -match "/$nfsexport ") |  out-string).split(' ')[3]
    }

    $fss = invoke-ssh "/nas/bin/nas_fs -info -all;uname -a" "GNU/Linux"
    $vls = invoke-ssh "/nas/bin/nas_volume -info -all;uname -a" "GNU/Linux"
    
    send-ssh "dm=$datamover"
    $temp = invoke-ssh '/nas/bin/server_stats $dm -c 1 -interval $interval -f csv -m $objects $ts;uname -a' "GNU/Linux"
    Remove-SshSession

    # make sure 0 exists in output
    [array]$temp2 = $temp | %{ $_.replace('""','"0"') }
    $temp = $temp2

    ## filter file system info for proper fields
    $data=$fss -match 'name   |volume  |disks   '

    ## parse filtered file system info and place into volume and disk hashes for later lookup
    $hashfsvolume = @{}
    $hashfsdisks = @{}
    for ($i=0;$i -lt $data.count;$i++) { 
        if ($data[$i] -match 'name    ') { 
            $name = $data[$i].replace(' ','').split('=')[1].TrimEnd()
            #$volume = $data[$i+1].replace(' ','').replace('v','').split('=')[1].TrimEnd()
            $volume = $data[$i+1].replace(' ','').split('=')[1].TrimEnd()
            $disks = $data[$i+2].replace(' ','').split('=')[1].TrimEnd()
            $hashfsvolume[$name] = $volume
            $hashfsdisks[$name] = $disks
        } 
    }

    $data=$vls -match 'id   |name   '
    $hashdnameid = @{}
    for ($i=0;$i -lt $data.count;$i++) { 
        if ($data[$i] -match 'id    ') { 
            $id = $data[$i].replace(' ','').split('=')[1].TrimEnd()
            $name = $data[$i+1].replace(' ','').split('=')[1].TrimEnd()
            $hashdnameid[$name] = $id
        } 
    }
       
    ## parse perfromance data for headers
    $arrHeader = @()
    $arrTemp = @()
    $hashValues = @{}

    $j = 0
    foreach ($line in $temp) {
        if($line.split(',').length -gt 1 -and !($line -match 'NAS_DB')) {
            $numHeader = $j
            break
        }
        $j++        
    }

    ## with header as first line grab sum and avg stats since has stats for all objects
    if ($numHeader) {
        $arrHeader = $temp[$j+2].replace('"','').split(',')
        $arrTemp = $temp[$j+4].replace('"','').split(',')

        for ($i=0;$i -lt $arrHeader.count;$i++) {
            $hashValues[$arrHeader[$i]] = $arrTemp[$i]
        }
            
        ## add in datamover
        $hashValues[$datamover] = ""        

        ## create a hash of the objects where each row has many metrics (std is one object linked to one metric)
        $arrMetric = @()
        $hashObjects = @{}

        
        $arrKeys = @()
        #$arrKeys += $hashValues.keys | where { $_ -match 'server_' } | sort
        $arrKeys += $hashValues.keys | where { $_ -match 'CPU' } | sort
        $arrKeys += $hashValues.keys | where { $_ -match 'Device' } | sort
        $arrKeys += $hashValues.keys | where { $_ -match '^NFS' } | sort
        $arrKeys += $hashValues.keys | where { $_ -match 'metaVol' } | sort
        $arrKeys += $hashValues.keys | where { $_ -match 'dVol' } | where {!($_ -match 'dVol Read|dVol Write')} | sort

        $x = 0
        
        $seenobject = @{}

        if (!$arrKeys) { write "didnt' get any stats to parse";exit }
        $ErrorActionPreference = "SilentlyContinue"

        $arrKeys | %{
            
            $item = $_
            if ($item -match 'Vol') {
                #take first two words
                $object = $item.split(' ')[0] + " " + $item.split(' ')[1]; 
                $metric = $item.replace($object+" ","")   
            } elseif ($item -match 'NFS') {
                #take only first word
                $object = $item.split(' ')[0]
                $metric = $item.replace($object+" ","")
            } else {
                #take first two words
                $object = $item.split(' ')[0] + " " + $item.split(' ')[1]; 
                $metric = $item.replace($object+" ","")                 
            }

            $metric = $metric -replace '^%', 'Util %'
            $metric = $metric.replace('Requests','Ops').trim()
            
            if (!$hashObjects[$object]) { $hashObjects[$object] = @{} }
            $hashObjects[$object].$metric = $hashValues[$_].trim()
            
            if (!$seenobject[$object]) { 
                $seenobject[$object] = @{}
                $hashObjects[$object].order = $x
                $x++ 
            }
            
            $arrMetric+=$metric;         
        }

        $ErrorActionPreference = "Continue"

        ## make the metric array unique        
        [array]$arrMetric = $arrMetric | sort | select -unique
            
        ## create output object and also create an aggregate array to make sure all columns are displayed
        $allstats = @()
        
        $outdate = get-date -f s
        $out = %{
            $hashObjects.keys | %{
                $obj = new-object PSObject
                $obj | Add-member Noteproperty -name Name -value $_
                $obj | Add-member Noteproperty -name order -value $hashObjects[$_].order
                $obj | Add-member Noteproperty -name Date -value $outdate

                ## use metric array so we fill in all columns
                foreach ($metric in $arrMetric) {
                    $obj | Add-member Noteproperty -name $metric -value $hashObjects[$_].$metric  
                    $allstats += $metric
                }
                write $obj
            }
        }

        if ($nfsexport) {            
            ## add the proper metadata to the object names that aligns with what server_stats is outputting        
            $arrgetvols = @()
            if([string]$version[$tline][0] -eq "5") { 
                $arrgetvols += $hashdnameid[$hashfsdisks[$nfsexport].split(',')] | %{ "dVol " + $_ }
                $arrgetvols += $hashfsvolume[$fs] | %{ "MetaVol " + $_.replace('v','') }
            } else { 
                $arrgetvols += $hashfsdisks[$nfsexport].split(',') | %{ "dVol " + $_ } 
                $arrgetvols += $hashfsvolume[$fs] | %{ "MetaVol " + $_ }
                $arrgetvols += "MetaVol " + $fs

            }

            ## combine the objects and doing matching to filter on what we want to see                
            $out = %{
                write $out | where {!($_.Name -match 'Vol') -and !($_.Name -match 'Summary')} | sort name  
                write $out | where {$arrgetvols -contains $_.Name} | sort name
            }
        }            
        
        [array]$allstats = $allstats | select -unique | sort
        
        if ($outcsv) {
            $csvpath = $path + $outcsv
            $csvcols = ""
            $coldate = get-date -f o
            write "Writing output to $csvpath with collection date of $coldate"

            [array]$newstats = "Date","Name"
            $allstats2 = @()
            [array]$allstats2 = $newstats + $allstats

            if(test-path $csvpath) {
                #$out |  %{ $csvout="";$trow=$_; $allstats2 | %{ $tt = $trow.$_; $csvout += "$tt," };$csvout.substring(0,$csvout.length-1) } | out-file -append $csvpath -encoding ascii
		[array]$csvstats = (get-content $csvpath -totalcount 1).split(',')
		$out | %{ 
			$trow = $_
			($csvstats | %{ $trow.$_ }) -join ',' | out-file -append $csvpath -encoding ascii
		}
            } else {
                #write the header and the data lines
                $allstats2 | %{ $csvcols += $_+"," }
                $csvcols.trim(',') | out-file $csvpath -encoding ascii
                $out |  %{ $csvout="";$trow=$_; $allstats2 | %{ $tt = $trow.$_; $csvout += "$tt," };$csvout.substring(0,$csvout.length-1) } | out-file -append $csvpath -encoding ascii

            }
        } else {    
            if ($paint -and $metrics) {
                clear;$out | sort order | select $metrics | ft *
            } elseif ($paint) {
                clear;$out | sort order | select * | ft *
            } elseif ($metrics) {
                $out | sort order | select $metrics
                exit
            } else {
                $out | sort order | select *
                exit
            }
        }
    } else {
        write-host failed to get a csv return, outputs below
        $temp
        $mounts
        $fss
        $vls
    }

sleep $sleep
}
